package org.koin.core.component;

import org.koin.core.Koin;
import org.koin.core.error.ClosedScopeException;
import org.koin.core.error.DefinitionParameterException;
import org.koin.core.error.NoBeanDefFoundException;
import org.koin.core.parameter.ParametersDefinition;
import org.koin.core.qualifier.Qualifier;
import org.koin.mp.KoinPlatformTools;

public interface KoinComponent {

    public static <S, P> S bind(KoinComponent component,
                                Class<S> sClass,
                                Class<P> pClass,
                                ParametersDefinition parameters)
            throws NoBeanDefFoundException {

        return component.getKoin().bind(sClass, pClass, parameters);
    }

    default Koin getKoin() {
        return KoinPlatformTools
                .INSTANCE()
                .defaultContext()
                .get();
    }

    default <T> T get(KoinComponent component,
                      Class<T> tClass,
                      Qualifier qualifier,
                      ParametersDefinition parameters)
            throws DefinitionParameterException,
            NoBeanDefFoundException,
            ClosedScopeException {

        if (component instanceof KoinScopeComponent) {
            return ((KoinScopeComponent) component).getScope()
                    .get(tClass, qualifier, parameters);
        } else {
            return component.getKoin().get(tClass, qualifier, parameters);
        }
    }

    default <T> T get(
            Class<T> tClass,
            Qualifier qualifier,
            ParametersDefinition parameters)
            throws DefinitionParameterException,
            NoBeanDefFoundException,
            ClosedScopeException {

        if (this instanceof KoinScopeComponent) {
            return ((KoinScopeComponent) this).getScope()
                    .get(tClass, qualifier, parameters);
        } else {
            return getKoin().get(tClass, qualifier, parameters);
        }
    }

    default <T> T get(
            Class<T> tClass) throws DefinitionParameterException,
            NoBeanDefFoundException,
            ClosedScopeException {

        return this.get(tClass, null, null);
    }
}
